package com.zn.collection
{
    import com.zn.events.ArrayCollectionEvent;
    
    import flash.events.EventDispatcher;
    
    import mx.events.PropertyChangeEvent;
    import mx.events.PropertyChangeEventKind;

    /**
     *集合
     * @author zn
     *
     */
    public class ArrayCollection extends EventDispatcher
    {
        public var source:Array;

		public var isDispatch:Boolean=true;
		
        public function ArrayCollection(list:Array = null)
        {
            if (list != null)
                source = list;
            else
                source = [];
        }

        public function addAll(addList:Array):void
        {
            var oldValue:Array = source.concat();
            source = source.concat(addList);

			if(isDispatch)
			{
	            var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.CHANGE, -1, source, oldValue);
	            dispatchEvent(event);
			}
			
            updateLength();
        }

        public function addAllAt(addList:Array, index:int):void
        {
            var oldValue:Array = source.concat();
            source.splice(index, 0, addList);

			if(isDispatch)
			{
	            var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.CHANGE, -1, source, oldValue);
	            dispatchEvent(event);
			}
			
            updateLength();
        }

        public function addItem(item:Object):void
        {
            source.push(item);

			if(isDispatch)
			{
	            var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.ADD, length, item, null);
	            dispatchEvent(event);
			}
			
            updateLength();
        }

        public function addItemAt(item:Object, index:int):void
        {
            source.splice(index, 0, item);

			if(isDispatch)
			{
	            var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.ADD, index, item, null);
	            dispatchEvent(event);
			}
			
            updateLength();
        }

        public function contains(item:Object):Boolean
        {
            var index:int = source.indexOf(item);
            return index != -1 ? true : false;
        }

        public function getItemAt(index:int):*
        {
            return source[index];
        }

        public function getItemIndex(item:Object):int
        {
            return source.indexOf(item);
        }

        public function removeAll():void
        {
            var oldArray:ArrayCollection = new ArrayCollection(source.concat());
            source.splice(0, length);

			if(isDispatch)
			{
	            var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.CHANGE, -1, null, oldArray);
	            dispatchEvent(event);
			}
			
            updateLength();
        }

        public function removeItem(item:Object):void
        {
            var index:int = source.indexOf(item);

            if (index != -1)
                removeItemAt(index);
        }

        public function removeItemAt(index:int):*
        {
			var list:Array = source.splice(index, 1);
			if(list.length==0)
				return null;
			
			var item:Object=list[0];

			if(isDispatch)
			{
	            var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.REMOVE, index, item, null);
	            dispatchEvent(event);
			}
			
            updateLength();

            return item;
        }

        public function removeSplice(start:int, length:int):ArrayCollection
        {
            if (length <= 0)
                return null;

            var oldArray:ArrayCollection = new ArrayCollection(source.splice(start, length));

			if(isDispatch)
			{
	            var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.CHANGE, -1, null, oldArray);
	            dispatchEvent(event);
			}
			
            updateLength();

            return oldArray;
        }

        public function setItemAt(item:Object, index:int):*
        {
            var oldValue:Object = source[index];

            source[index] = item;

			if(isDispatch)
			{
	            var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.REPLACE, index, item, oldValue);
	            dispatchEvent(event);
			}
			
            return oldValue;
        }

        public function toArray():Array
        {
            return source.concat();
        }

        public override function toString():String
        {
            return source.toString();
        }

        public function reverse():ArrayCollection
        {
            var oldValue:Object = source.concat();
            var newValue:Array = source.reverse();

			if(isDispatch)
			{
	            var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.CHANGE, -1, newValue, oldValue);
	            dispatchEvent(event);
			}
			
            updateLength();

            return new ArrayCollection(newValue);
        }

        /**
         *
         *
         *  function callback(item:*, index:int, array:Array):Boolean;
           {
           //your code here
           }

         *
         * @param callback
         * @return
         *
         */
        public function filter(callback:Function):ArrayCollection
        {
            return new ArrayCollection(source.filter(callback));
        }

        public function sort(... parameters):ArrayCollection
        {
            var oldValue:Array = source.concat();

            var result:Object = source["sort"].apply(source, parameters);

            var arg:int;
            if (parameters.length != 0)
                arg = parameters[0];

            if (result != 0 && (arg & Array.RETURNINDEXEDARRAY) != Array.RETURNINDEXEDARRAY)
            {
				if(isDispatch)
				{
	                var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.CHANGE, -1, result, oldValue);
	                dispatchEvent(event);
				}
				
                updateLength();
            }

            if (result is Array)
                return new ArrayCollection(result as Array);
            else
                return null;
        }

        public function sortOn(fieldName:Object, options:Object = null):ArrayCollection
        {
            var oldValue:Array = source.concat();

            var result:Object = source["sortOn"].call(source, fieldName, options);

            var arg:int;
            if (options is Array && options.length != 0)
                arg = options[0];
            else
                arg = options as int;

            if (result != 0 && (arg & Array.RETURNINDEXEDARRAY) != Array.RETURNINDEXEDARRAY)
            {
				if(isDispatch)
				{
	                var event:ArrayCollectionEvent = new ArrayCollectionEvent(ArrayCollectionEvent.CHANGE, -1, result, oldValue);
	                dispatchEvent(event);
				}
				
                updateLength();
            }

            if (result is Array)
                return new ArrayCollection(result as Array);
            else
                return null;
        }

        public function get length():int
        {
            return source.length;
        }

        protected function updateLength():void
        {
			if(isDispatch)
			{
            	dispatchEvent(new PropertyChangeEvent(PropertyChangeEvent.PROPERTY_CHANGE, false, false, PropertyChangeEventKind.UPDATE, "length", length));
			}
        }
    }
}